package cn.tedu.luban.worker.main.repository.Impl;

import cn.tedu.luban.worker.main.converter.WorkerConverter;
import cn.tedu.luban.worker.main.mapper.WorkerMapper;
import cn.tedu.luban.worker.main.repository.IWorkerRepository;
import cn.tedu.luban.worker.protocol.bo.AdminWorkerBO;
import cn.tedu.luban.worker.protocol.bo.FrontWorkerBO;
import cn.tedu.luban.worker.protocol.dos.WorkerDO;
import cn.tedu.luban.worker.protocol.param.WorkerParam;
import cn.tedu.luban.worker.protocol.param.WorkerRegistParam;
import cn.tedu.luban.worker.protocol.query.WorkerDBPageQuery;
import cn.tedu.luban.worker.protocol.query.WorkerListQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

//仓储层处理的是数据,但是处理数据实现 到底redis的数据 mysql es 仓储层不关心,由实现去关心
@Repository
@Slf4j
public class WorkerRepositoryImpl implements IWorkerRepository {
    @Autowired(required = false)
    private WorkerMapper workerMapper;
    @Autowired
    private WorkerConverter workerConverter;
    @Override
    public void delete(Long userId) {
        //调用持久层 删除userId对应的师傅数据
        //持久层方法尽可能满足一些常用命名规范 做到见名知sql
        workerMapper.deleteByUserId(userId);
        //删除缓存
        redisTemplate.delete("luban:worker:detail:"+userId);
    }

    @Override
    public Long save(WorkerRegistParam param) {
        //1.param里的师傅数据 取出转化成WorkerDO
        //可以直接使用param参数四个 idCard realName userId phone
        //status cert_status audit_status 6个通用字段
        WorkerDO workerDO=workerConverter.param2do(param);
        //2.调用持久层写入
        workerMapper.insert(workerDO);
        //3.userId 查询workerDO mybatis有一个功能,让入参DO对象 id主键自动封装自增的结果
        //无序操作缓存
        return workerDO.getId();
    }
    @Autowired
    private RedisTemplate redisTemplate;//key值可以是任意object value值任意的object list元素 hash field value都是可以任意object
    @Override
    public FrontWorkerBO findWorker(Long userId) {
        //使用String redis数据类型 存储key-value的数据
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //1. 查询缓存
        String workerKey="luban:worker:detail:"+userId;
        //判断是否命中 exists key 返回1 表示存在 返回0 表示不存在
        Boolean hasKey = redisTemplate.hasKey(workerKey);
        FrontWorkerBO workerBO =null;
        if (!hasKey){
            log.info("查询数据库,缓存没命中,key值:{}",workerKey);
            //2. 没命中读取数据库
            //调用持久层方法sql select * from worker where user_id=#{userId}
            //持久层 查询返回结果 是do 做转化
            WorkerDO workerDO=workerMapper.selectByUserId(userId);
            workerBO = workerConverter.do2frontBo(workerDO);
            //3. 存储补充缓存 是否允许永久存储. redis节省内存 给一个超时时间
            valueOperations.set(workerKey,workerBO,60*60*24+new Random().nextInt(60*60*12), TimeUnit.SECONDS);
        }else{
            log.info("缓存命中,直接返回缓存数据,key值:{}",workerKey);
            //缓存命中 直接读缓存数据
            workerBO= (FrontWorkerBO) valueOperations.get(workerKey);
        }
        log.info("读取workerBO:{}",workerBO);
        return workerBO;
    }

    @Override
    public Long countWorker(WorkerListQuery query) {
        //1. 入参query 不是持久层分页查询的入参 需要转化 换成dbQuery String limit="limit 0,10"
        WorkerDBPageQuery dbQuery = workerConverter.query2dbQuery(query);
        //利用pageNo和pageSize 拼接了limit关键字 limit (pageNo-1)*pageSize,pageSize
        String limit = dbQuery.getLimit();
        log.info("dbQuery拼接的limit参数:{}",limit);
        //2. 调用持久层 查询
        Long total=workerMapper.countWorker(dbQuery);
        return total;
    }

    @Override
    public List<AdminWorkerBO> findPageWorkers(WorkerListQuery query) {
        //1. 入参query 不是持久层分页查询的入参 需要转化 换成dbQuery String limit="limit 0,10"
        WorkerDBPageQuery dbQuery = workerConverter.query2dbQuery(query);
        //2. 持久层 查询分页列表 listDO
        List<WorkerDO> dos=workerMapper.selectWorkers(dbQuery);
        return workerConverter.dos2bos(dos);
    }

    @Override
    public AdminWorkerBO findAdminWorker(Long userId) {
        WorkerDO workerDO=workerMapper.selectByUserId(userId);
        return workerConverter.do2bo(workerDO);
    }
    private static final String WORKER_DETAIL_PREFIX="luban:worker:detail:";
    //写操作  由于在当前仓储层 使用了缓存 所以要满足cache-aside流程要求
    //写流程 先执行数据库写,在删除缓存
    //worker worker_area也相同
    @Override
    public void updateAuditStatus(WorkerParam workerParam) {
        //1. param转化成持久层入参 do
        WorkerDO workerDO = workerConverter.param2do(workerParam);
        //2. 调用持久层修改
        workerMapper.updateAuditStatus(workerDO);
    }

    @Override public void updateCertStatus(WorkerParam param) {
        WorkerDO workerDO = workerConverter.param2do(param);
        workerMapper.updateCertStatus(workerDO);
        redisTemplate.delete(WORKER_DETAIL_PREFIX+param.getUserId());
    }
}
